﻿using Microsoft.Extensions.Configuration;
using Microsoft.Extensions.DependencyInjection;
using Microsoft.Extensions.Logging;
using Newtonsoft.Json;
using Quartz;
using System.Web;
using TaskMasterByQuartz.Domain.Entities;
using TaskMasterByQuartz.Domain.Enums;
using TaskMasterByQuartz.Domain.Helper;
using TaskMasterByQuartz.Domain.ServiceRepository;
using TaskMasterByQuartz.Infrastructure.DbContext;

namespace TaskMasterByQuartz.Infrastructure.Implementations
{
    [DisallowConcurrentExecution]
    [PersistJobDataAfterExecution]
    public class MyHttpJob : IJob
    {
        private readonly ILogger<MyHttpJob> _logger;
        private readonly IConfiguration _configuration;
        private readonly IServiceProvider _serviceProvider;
        private readonly IServiceScope serviceScope;

        public MyHttpJob(ILogger<MyHttpJob> logger, IConfiguration configuration, IServiceProvider serviceProvider, IServiceScopeFactory serviceProviderFactory)
        {
            _logger = logger;
            _configuration = configuration;
            this.serviceScope = serviceProviderFactory.CreateScope();
            this._serviceProvider = serviceScope.ServiceProvider;
        }

        public async Task Execute(IJobExecutionContext context)
        {
            _logger.LogInterpolatedInformation($"执行定时任务");
            var logInfo = new ExecuteLog();
            //如果结束时间超过当前时间，则暂停当前任务。
            var jobEndTime = context.JobDetail.JobDataMap.GetString("EndAt");
            if (!string.IsNullOrWhiteSpace(jobEndTime) && DateTime.Parse(jobEndTime) <= DateTime.Now)
            {
                await context.Scheduler.PauseJob(new JobKey(context.JobDetail.Key.Name, context.JobDetail.Key.Group));
                return;
            }

            try
            {
                logInfo.Init1(context.JobDetail.Key.Group, context.JobDetail.Key.Name);
                //获取相关参数
                var requestUrl = context.JobDetail.JobDataMap.GetString(Constant.REQUESTURL)?.Trim();
                logInfo.Init2(requestUrl);
                requestUrl = requestUrl?.IndexOf("http") == 0 ? requestUrl : "http://" + requestUrl;
                var requestParameters = context.JobDetail.JobDataMap.GetString(Constant.REQUESTPARAMETERS);
                var headersString = context.JobDetail.JobDataMap.GetString(Constant.HEADERS);
                var headers = headersString != null ? JsonConvert.DeserializeObject<Dictionary<string, string>>(headersString?.Trim()) : null;
                var requestType = (RequestTypeEnum)Enum.Parse(typeof(RequestTypeEnum), context.JobDetail.JobDataMap.GetString(Constant.REQUESTTYPE));

                // 执行
                HttpResponseMessage response = new HttpResponseMessage();
                var http = HttpHelper.Instance;
                switch (requestType)
                {
                    case RequestTypeEnum.Get:
                        response = await http.GetAsync(requestUrl, headers);
                        break;
                    case RequestTypeEnum.Post:
                        response = await http.PostAsync(requestUrl, requestParameters, headers);
                        break;
                    case RequestTypeEnum.Put:
                        response = await http.PutAsync(requestUrl, requestParameters, headers);
                        break;
                    case RequestTypeEnum.Delete:
                        response = await http.DeleteAsync(requestUrl, headers);
                        break;
                }
                var result = HttpUtility.HtmlEncode(await response.Content.ReadAsStringAsync());

                // 日志写入
                logInfo.Statu = response.StatusCode == System.Net.HttpStatusCode.OK ? ExecuteStatuEnum.Success : logInfo.Statu = ExecuteStatuEnum.Fail;
                logInfo.Result = result;
            }
            catch (Exception ex)
            {
                logInfo.Result = ex.Message;
                logInfo.Statu = ExecuteStatuEnum.Fail;
            }
            finally
            {

                // 计算执行时常
                logInfo.SetEndTime();

                // 新方案
                // 通过依赖注入容器的作用域（IServiceProvider）和作用域工厂（IServiceScopeFactory）来实现注入
                // 使用的是自己搭建的VNext。DbContext默认是注入Scope类型：services.AddAllDbContexts
                using var scope = this._serviceProvider.CreateScope();
                var dbContext = scope.ServiceProvider.GetService<MyDbContext>();
                await dbContext.AddAsync(logInfo);
                await dbContext.SaveChangesAsync();

                // 旧方案
                //string connectionString = _configuration.GetConnectionString("QuartzConnStr");
                //var optionsBuilder = DbContextOptionsBuilderFactory.Create<MyDbContext>(connectionString);
                //using (var dbContext = new MyDbContext(optionsBuilder.Options, null))
                //{
                //    await dbContext.AddAsync(logInfo);
                //    await dbContext.SaveChangesAsync();
                //}
            }
        }
    }
}
